//
//  Model3D_obj_Importer.cpp
//  C3W_Demo_By_Fan
//
//  Created by 范静涛 on 2024/7/21.
//

//------------------------------------------------------------------------------
//【文件名】Model3D_obj_Importer.cpp
//【功能模块和目的】导入obj文件到Model3D的导入器类实现
//【开发者及日期】范静涛 2024/7/21
//【更改记录】
//------------------------------------------------------------------------------

//自身类头文件
#include "Model3D_obj_Importer.hpp"
//Importer基类模版所属头文件
#include "Importer.hpp"
//Model3D类所属头文件
#include "Model3D.hpp"
//Point3D类所属头文件
#include "Point3D.hpp"
//Face3D类所属头文件
#include "Face3D.hpp"
//Line3D类所属头文件
#include "Line3D.hpp"
//std::ifstream所属头文件
#include <fstream>
//StringList所属头文件
#include "StringList.hpp"
//std::vector所属头文件
#include <vector>

//------------------------------------------------------------------------------
//必要的构造、析构、赋值行为
//------------------------------------------------------------------------------

//函数名：Model3D_obj_Importer
//功能：默认构造函数，手动触发基类构造函数，指定文件扩展名为"obj"
//入口参数：无
//出口参数：无
//返回值：无
Model3D_obj_Importer::Model3D_obj_Importer()
: Importer<Model3D>(std::string("obj")){
}

//--------------------------------------------------------------------------
//受保护的 非静态Getter成员函数：需检查所有Getter是否有后置const
//--------------------------------------------------------------------------

//函数名：LoadFromStream const
//功能：从文件流导入到Model3D对象接口override
//入口参数：std::ifstream& Stream
//出口参数：无
//返回值：Model3D对象
Model3D Model3D_obj_Importer::LoadFromStream(std::ifstream& Stream) const{
    //临时，空模型对象
    Model3D TempModel;
    //点线面队列
    std::vector<Point3D> Points;
    std::vector<Face3D>  Faces;
    std::vector<Line3D>  Lines;
    //'#','g','v','l','f'等标签
    char Tag;
    //注释
    std::string Comment;
    //点的三坐标
    double XVal{0};
    double YVal{0};
    double ZVal{0};
    //点的索引
    unsigned int Index1{0};
    unsigned int Index2{0};
    unsigned int Index3{0};
    //文件流不空，则继续读取
    while(!Stream.eof()){
        //清空标签
        Tag = 0;
        //读入标签
        Stream >> Tag;
        //抛弃标签后空格
        Stream.get();
        //标签分类判断
        switch (Tag) {
            //读到注释行
            case '#':
                //从文件流中读入注释内容（吃掉了换行符）
                getline(Stream, Comment);
                //向临时模型中加入注释内容
                TempModel.Comments.Append(Comment);
                break;
            //读到名称行
            case 'g':
                //从文件流中读入名称并存入临时模型（吃掉了换行符）
                getline(Stream, TempModel.Name);
                break;
            //读到点数据
            case 'v':
                //依次读入3个坐标
                Stream >> XVal >> YVal >> ZVal;
                //丢弃后面的换行符
                Stream.get();
                //加入点队列
                Points.push_back(Point3D(XVal, YVal, ZVal));
                break;
            //读到线数据
            case 'l':
                //依次读入2个索引
                Stream >> Index1 >> Index2;
                //丢弃后面的换行符
                Stream.get();
                //加入线队列
                Lines.push_back(Line3D(Points[Index1 - 1], Points[Index2 - 1]));
                break;
            //读到面数据
            case 'f':
                //依次读入3个索引
                Stream >> Index1 >> Index2 >> Index3;
                //丢弃后面的换行符
                Stream.get();
                //加入面队列
                Faces.push_back(Face3D(
                    Points[Index1 - 1],
                    Points[Index2 - 1],
                    Points[Index3 -1 ]));
          }
    }
    //向临时模型合并所有面
    TempModel += Faces;
    //向临时模型合并所有线
    TempModel += Lines;
    //返回临时模型
    return TempModel;
}
